package com.a1anwang.okble.demo.ability;

import com.a1anwang.okble.common.*;
import com.a1anwang.okble.demo.ResourceTable;
import com.a1anwang.okble.demo.base.BaseAbility;
import com.a1anwang.okble.demo.utils.TextUtilsEx;
import com.a1anwang.okble.demo.utils.ToastUtil;
import com.a1anwang.okble.demo.views.HexInputPopupWindow;
import com.a1anwang.okble.demo.views.ServiceDataInputPopupWindow;
import com.a1anwang.okble.demo.views.ServiceUUIDInputPopupWindow;
import com.a1anwang.okble.server.advertise.OKBLEAdvertiseCallback;
import com.a1anwang.okble.server.advertise.OKBLEAdvertiseData;
import com.a1anwang.okble.server.advertise.OKBLEAdvertiseManager;
import com.a1anwang.okble.server.advertise.OKBLEAdvertiseSettings;
import com.a1anwang.okble.server.core.OKBLEServerDevice;
import com.a1anwang.okble.server.core.OKBLEServerDeviceImp;
import com.a1anwang.okble.server.core.OKBLEServerOperation;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextTool;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.window.service.DisplayManager;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.utils.SequenceUuid;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by a1anwang.com on 2018/5/30.
 */
public class AdvertiseAbility extends BaseAbility {
    OKBLEAdvertiseManager okbleAdvertiseManager;
    OKBLEServerDevice serverDevice;
    private Image btLeft;
    private Switch switchConnectable;
    private Switch switchIncludename;
    private TextField tvCompanyId;
    private String beginCompanyId;

    @Override
    public boolean isFullScreen() {
        return false;
    }

    @Override
    public void setContentLayout() {
        setUIContent(ResourceTable.Layout_ability_advertise);
    }

    @Override
    public void beforeInitView() {
        okbleAdvertiseManager = new OKBLEAdvertiseManager(this);
        serverDevice = new OKBLEServerDeviceImp(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        okbleAdvertiseManager.stopAdvertising();
    }

    @Override
    public void initView() {
        tvCompanyId = (TextField) findComponentById(ResourceTable.Id_tv_company_id);
        tvCompanyId.addTextObserver(new Text.TextObserver() {
            @Override
            public void onTextUpdated(String s, int i, int i1, int i2) {
                if (!isNumeric(s)) {
                    tvCompanyId.setText(beginCompanyId);
                    return;
                }
                beginCompanyId = s;
            }
        });
        btLeft = (Image) findComponentById(ResourceTable.Id_btn_left);
        switchConnectable = (Switch) findComponentById(ResourceTable.Id_switch_connectable);
        switchIncludename = (Switch) findComponentById(ResourceTable.Id_switch_includename);
        btLeft.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                onBackPressed();
            }
        });
        setHeadVisibility(Component.VISIBLE);
        setTitle("Work as a peripheral");
        findComponentById(ResourceTable.Id_btn_start).setClickedListener(this);
        findComponentById(ResourceTable.Id_btn_stop).setClickedListener(this);
        findComponentById(ResourceTable.Id_btn_add_service_uuid).setClickedListener(this);
        findComponentById(ResourceTable.Id_btn_add_service_data).setClickedListener(this);
        findComponentById(ResourceTable.Id_tv_company_value).setClickedListener(this);
        ShapeElement elementThumbOn = new ShapeElement();
        elementThumbOn.setShape(ShapeElement.OVAL);
        elementThumbOn.setRgbColor(RgbColor.fromArgbInt(0xFFFF4081));
        elementThumbOn.setCornerRadius(50);
        ShapeElement elementThumbOff = new ShapeElement();
        elementThumbOff.setShape(ShapeElement.OVAL);
        elementThumbOff.setRgbColor(RgbColor.fromArgbInt(0xFFFFFFFF));
        elementThumbOff.setCornerRadius(50);
        ShapeElement elementTrackOn = new ShapeElement();
        elementTrackOn.setShape(ShapeElement.RECTANGLE);
        elementTrackOn.setRgbColor(RgbColor.fromArgbInt(0xFFF6CEE3));
        elementTrackOn.setCornerRadius(50);
        ShapeElement elementTrackOff = new ShapeElement();
        elementTrackOff.setShape(ShapeElement.RECTANGLE);
        elementTrackOff.setRgbColor(RgbColor.fromArgbInt(0xFFBDBDBD));
        elementTrackOff.setCornerRadius(50);
        switchConnectable.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchConnectable.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));
        switchIncludename.setTrackElement(trackElementInit(elementTrackOn, elementTrackOff));
        switchIncludename.setThumbElement(thumbElementInit(elementThumbOn, elementThumbOff));
    }

    @Override
    public void afterInitView() {

    }

    private StateElement trackElementInit(ShapeElement on, ShapeElement off) {
        StateElement trackElement = new StateElement();
        trackElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, on);
        trackElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, off);
        return trackElement;
    }

    private StateElement thumbElementInit(ShapeElement on, ShapeElement off) {
        StateElement thumbElement = new StateElement();
        thumbElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, on);
        thumbElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, off);
        return thumbElement;
    }

    @Override
    public void onClickEvent(Component v) {
        switch (v.getId()) {
            case ResourceTable.Id_btn_start:
                startAdvertising();
                break;
            case ResourceTable.Id_btn_stop:

                if (okbleAdvertiseManager != null) {
                    okbleAdvertiseManager.stopAdvertising();
                    serverDevice.reSet();
                }
                break;
            case ResourceTable.Id_btn_add_service_uuid:
                showInput();
                break;
            case ResourceTable.Id_btn_add_service_data:
                showDataInput();
                break;
            case ResourceTable.Id_tv_company_value:
                showCompanyDataInput();
                break;
            default:
                break;
        }
    }


    private void showInput() {
        ServiceUUIDInputPopupWindow popupWindow = new ServiceUUIDInputPopupWindow(this);
        popupWindow.showAt();
        popupWindow.setInputListener(new ServiceUUIDInputPopupWindow.InputListener() {
            @Override
            public void onInputComplete(String value) {
                if (OKBLEDataUtils.isValidShortUUID(value) || OKBLEDataUtils.isValidUUID(value)) {
                    addServiceUuId(value);
                }
            }
        });
    }

    private void showDataInput() {
        ServiceDataInputPopupWindow popupWindow = new ServiceDataInputPopupWindow(this);
        popupWindow.showAt();
        popupWindow.setInputListener(new ServiceDataInputPopupWindow.InputListener() {
            @Override
            public void onInputComplete(String uuid, String value) {
                if ((OKBLEDataUtils.isValidShortUUID(uuid) || OKBLEDataUtils.isValidUUID(uuid))
                        && !TextUtilsEx.isEmpty(value)) {
                    addServiceData(uuid, value);
                }
            }
        });
    }

    private void showCompanyDataInput() {
        HexInputPopupWindow popupWindow = new HexInputPopupWindow(this);
        popupWindow.showAt();
        popupWindow.setInputListener(new HexInputPopupWindow.InputListener() {
            @Override
            public void onInputComplete(String value) {
                Text tv = (Text) findComponentById(ResourceTable.Id_tv_company_value);
                tv.setText(value);
            }
        });
    }

    private void addServiceUuId(String value) {
        final DirectionalLayout linelayoutServiceUuid =
                (DirectionalLayout) findComponentById(ResourceTable.Id_linelayout_service_uuid);
        final Text textView = new Text(mContext);
        textView.setTextSize(40);
        textView.setTextColor(new Color(Color.getIntColor("#888888")));
        textView.setText(value);
        textView.setMultipleLine(true);
        linelayoutServiceUuid.addComponent(textView, 0, new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT));
        textView.setClickedListener(v -> linelayoutServiceUuid.removeComponent(textView));
    }

    private void addServiceData(String uuid, String value) {
        final DirectionalLayout linelayoutServiceData =
                (DirectionalLayout) findComponentById(ResourceTable.Id_linelayout_service_data);
        final Text textView = new Text(mContext);
        textView.setTextSize(40);
        textView.setMultipleLine(true);
        textView.setTextColor(new Color(Color.getIntColor("#888888")));
        textView.setText(uuid + ":" + value);
        linelayoutServiceData.addComponent(textView, 0, new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT));
        textView.setClickedListener(component -> linelayoutServiceData.removeComponent(textView));
    }

    private boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    private void startAdvertising() {
        if (!tvCompanyId.getText().isEmpty()) {
            if (Double.parseDouble(tvCompanyId.getText()) > 250) {
                ToastUtil.toast(this, "company_id输入应小于250");
                return;
            }
        }
        boolean connectable = switchConnectable.isChecked();
        boolean includename = switchIncludename.isChecked();
        OKBLEAdvertiseSettings settings = new OKBLEAdvertiseSettings.Builder().setConnectable(connectable).build();
        OKBLEAdvertiseData.Builder dataBuilder = new OKBLEAdvertiseData.Builder().setIncludeDeviceName(includename);
        DirectionalLayout linelayoutServiceUuid = (DirectionalLayout) findComponentById(ResourceTable.Id_linelayout_service_uuid);
        int serviceUuidCount = linelayoutServiceUuid.getChildCount() - 1;
        for (int i = 0; i < serviceUuidCount; i++) {
            Text tv = (Text) linelayoutServiceUuid.getComponentAt(i);
            SequenceUuid uuid = CommonUUIDUtils.createUUIDByShortOrCompleteUUIDStr(tv.getText().toString());
            if (uuid != null) {
                dataBuilder.addServiceUuid(uuid);
            }
        }
        DirectionalLayout linelayoutServiceData = (DirectionalLayout) findComponentById(ResourceTable.Id_linelayout_service_data);
        int serviceDataCount = linelayoutServiceData.getChildCount() - 1;
        for (int i = 0; i < serviceDataCount; i++) {
            Text tv = (Text) linelayoutServiceData.getComponentAt(i);
            String[] strings = tv.getText().split(":");
            if (strings.length == 2) {
                String uuidStr = strings[0];
                String dataStr = strings[1];
                SequenceUuid uuid = CommonUUIDUtils.createUUIDByShortOrCompleteUUIDStr(uuidStr);
                if (uuid != null) {
                    dataBuilder.addServiceData(uuid, OKBLEDataUtils.hexStringToBytes(dataStr));
                }
            }
        }

        Text tvCompanyValue = (Text) findComponentById(ResourceTable.Id_tv_company_value);
        String companyId = tvCompanyId.getText();
        String companyValue = tvCompanyValue.getText();
        if (!TextTool.isNullOrEmpty(companyId) && !TextTool.isNullOrEmpty(companyValue) && TextUtilsEx.isDigitsOnly(companyId)) {
            dataBuilder.addManufacturerData(Integer.valueOf(companyId), OKBLEDataUtils.hexStringToBytes(companyValue));
        }
        OKBLEAdvertiseData okbleAdvertiseData = dataBuilder.build();
        okbleAdvertiseManager.startAdvertising(settings, okbleAdvertiseData, new OKBLEAdvertiseCallback() {
            @Override
            public void onStartSuccess() {
                LogUtils.e("---onStartSuccess ---");
                new EventHandler(EventRunner.getMainEventRunner()).postTask(() ->
                        ToastUtil.toast(mContext, "Advertising Success"));
            }

            @Override
            public void onStartFailure(int errorCode, String errMsg) {
                LogUtils.e("---onStartFailure errMsg:" + errMsg);
                int screenWidht = DisplayManager.getInstance().getDefaultDisplay(mContext).get().getAttributes().width;
                DirectionalLayout toastLayout = (DirectionalLayout) LayoutScatter.getInstance(mContext)
                        .parse(ResourceTable.Layout_layout_toast, null, false);
                Text msg_toast = (Text) toastLayout.findComponentById(ResourceTable.Id_msg_toast);

                msg_toast.setText("Advertising Failed:" + errMsg);
                new ToastDialog(mContext).setComponent(toastLayout)
                        .setSize((int) (screenWidht * 0.7), DirectionalLayout.LayoutConfig.MATCH_CONTENT).show();
            }
        });
    }

    private void configServer() {
        OKBLEServiceModel serviceModel = new OKBLEServiceModel(CommonUUIDUtils.createCompleteUUIDByShortUUID("fff0"));
        OKBLECharacteristicModel characteristicModel = new OKBLECharacteristicModel(CommonUUIDUtils.createCompleteUUIDByShortUUID("fff1"));
        characteristicModel.setCanWrite(true);
        characteristicModel.setCanNotify(true);
        characteristicModel.setCanRead(true);
        OKBLECharacteristicModel characteristicModelTwO = new OKBLECharacteristicModel(CommonUUIDUtils.createCompleteUUIDByShortUUID("fff2"));
        characteristicModelTwO.setCanWriteNoResponse(true);
        List<OKBLECharacteristicModel> characteristicModels = new ArrayList<>();
        characteristicModels.add(characteristicModel);
        characteristicModels.add(characteristicModelTwO);
        serverDevice.addCharacteristic(characteristicModels, serviceModel, new OKBLEServerOperation.BLEServerOperationListener() {
            @Override
            public void onAddCharacteristicFailed(int errorCode, String errorMsg) {
                LogUtils.e("onAddCharacteristicFailed:" + errorMsg);
            }

            @Override
            public void onAddCharacteristicSuccess() {
                LogUtils.e("onAddCharacteristicSuccess");
            }
        });
    }
}
